﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace LANmine
{
    public partial class ComposForm : Form
    {
        private Language lmLang;
        private User lmUser;
        private Database roDb = new Database("ro");
        private Database rwDb = new Database("rw");

        /**
         * Holds the database ID of the currently selected game
         * Initialized to 0, a value an ID field can never have.
         */
        public UInt32 SelectedGame { get; set; }

        /**
         * ComposForm::Constructor
         */
        public ComposForm(Language lmLang, User lmUser)
        {
            /** Save objects */
            this.lmLang = lmLang;
            this.lmUser = lmUser;

            /** Dock the window */
            this.Dock = DockStyle.Fill;

            /** Initialize the Game ListView pointer */
            this.SelectedGame = 0;

            InitializeComponent();
            ApplyLanguage();
        }

        #region Language Specifications
        /**
         * MainForm::ApplyLanguage()
         * ---------------------------
         * Overwrite all text properties of all elements in all forms with the right ones.
         */
        private void ApplyLanguage()
        {
            /**
             * Header label
             */
            this.lblCompos.Text = this.lmLang.GetString("menu.btnCompos");
            /**
             * other labels & buttons
             */
            this.btnCreateTeam.Text = this.lmLang.GetString("compos.btnCreateTeam");
            this.btnRegister.Text = this.lmLang.GetString("compos.btnRegister");
        }
        #endregion

        #region Member Functions
        /**
         * ComposForm::LoadGames
         * Fetch a list of games from the database, including their metadata.
         */
        private void loadGames(ListView lvw)
        {
            /** Define temp variables */
            UInt16 gSize;
            String gName;
            String gSign;

            /** Define database objects */
            DataSet ds = new DataSet();
            DataTable dt;
            SqlConnection dbConn = this.roDb.getDbConn();
            SqlDataAdapter da;

            /** Open database connection */
            dbConn.Open();

            /** Create DataAdapter */
            da = new SqlDataAdapter("SELECT *, dbo.GetSignups(id) AS signups FROM games", dbConn);

            /** Close the database connection, not needed anymore */
            dbConn.Close();

            /** Fill the dataset with the incoming data and put it into the 'games' table */
            da.Fill(ds, "games");

            /** Extract the table from the DataSet */
            dt = ds.Tables["games"];

            /** Add three columns */
            lvw.Columns.AddRange(new ColumnHeader[] { new ColumnHeader(), new ColumnHeader(), new ColumnHeader() });

            /** Add groups with the given names */
            lvw.Groups.Add(new ListViewGroup("solo", lmLang.GetString("compos.lvwGamesSolo")));
            lvw.Groups.Add(new ListViewGroup("team", lmLang.GetString("compos.lvwGamesTeam")));

            foreach (DataRow r in dt.Rows)
            {
                /** Prepare Data */
                gSize = Convert.ToUInt16(r["teamgrootte"].ToString());
                gName = r["short"].ToString();

                if(gSize > 1)
                    gSign = r["signups"].ToString() + " " + lmLang.GetString("compos.lvwGamesTeamSign");
                else
                    gSign = r["signups"].ToString() + " " + lmLang.GetString("compos.lvwGamesCompSign");

                /** Generate ListViewItem based on the database row */
                ListViewItem cItem = new ListViewItem(new string[] { r["naam"].ToString(), gSize + "v" + gSize, gSign });

                /**
                 * Tag the current entry with the ID, for easy database lookups.
                 * Also, the "name" can be used to easily handle an entry afterwards.
                 */
                cItem.Tag = r["id"].ToString();
                cItem.Name = r["short"].ToString();

                /** Push the current item to the team game group */
                lvw.Items.Add(cItem);

                /** Assign the added game to the correct group */
                if (gSize > 1)
                    lvw.Items[gName].Group = lvwGames.Groups["team"];
                else
                    lvw.Items[gName].Group = lvwGames.Groups["solo"];
            }
        }

        /**
         * ComposForm::loadTeams
         * Load a list of teams for the given game ID into the given ListView.
         */
        private void loadTeams(String gId, ListView lvw)
        {
            /** Define database objects */
            DataSet ds = new DataSet();
            DataTable dt;
            SqlConnection dbConn = this.roDb.getDbConn();
            SqlDataAdapter da;

            /** Add two columns to the ListView */
            lvw.Columns.AddRange(new ColumnHeader[] { new ColumnHeader(), new ColumnHeader() });

            try
            {
                /** Open database connection */
                dbConn.Open();

                da = new SqlDataAdapter("EXEC lmGetGameTeams @GameId = '" + gId + "'", dbConn);

                /** Free up the database connection */
                dbConn.Close();

                /** Fill the DataSet from the DataAdapter */
                da.Fill(ds, "teams");

                /** Extract the teams table from the dataset */
                dt = ds.Tables["teams"];

                /** Add a group to clarify the meaning of the ListView */
                ListViewGroup sGroup = new ListViewGroup("team", lmLang.GetString("compos.lvwTeamsTeamsTitle") + dt.Rows.Count);
                lvw.Groups.Add(sGroup);

                /** Check for empty result set */
                if (dt.Rows.Count > 0)
                {
                    /** Loop through a list of teams */
                    foreach (DataRow r in dt.Rows)
                    {
                        /** Add the current record to the ListView */
                        lvw.Items.Add(new ListViewItem(new String[] { r["naam"].ToString(), lmLang.GetString("compos.miscCaptain") + ": " + r["gebruikersnaam"].ToString() }, sGroup));
                    }
                }
                else
                {
                    /** Add an empty record */
                    lvw.Items.Add(new ListViewItem(lmLang.GetString("compos.errNoTeams"), sGroup));
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(lmLang.GetString("compos.errTeamList") + "\n" + e.Message);
            }
        }

        /**
         * ComposForm::loadCompetitors
         * Load a list of competitors for the given game ID into the given ListView.
         */
        private void loadCompetitors(String gId, ListView lvw)
        {
            /** Define database objects */
            DataSet ds = new DataSet();
            DataTable dt;
            SqlConnection dbConn = this.roDb.getDbConn();
            SqlDataAdapter da;

            /** Add two columns to the ListView */
            lvw.Columns.AddRange(new ColumnHeader[] { new ColumnHeader(), new ColumnHeader() });

            try
            {
                /** Open database connection */
                dbConn.Open();

                da = new SqlDataAdapter("EXEC lmGetGameCompetitors @GameId = '" + gId + "'", dbConn);

                /** Free up the database connection */
                dbConn.Close();

                /** Fill the DataSet from the DataAdapter */
                da.Fill(ds, "comps");

                /** Extract the teams table from the dataset */
                dt = ds.Tables["comps"];

                /** Add a group to clarify the meaning of the ListView */
                ListViewGroup sGroup = new ListViewGroup("solo", lmLang.GetString("compos.lvwTeamsCompsTitle") + dt.Rows.Count);
                lvw.Groups.Add(sGroup);

                if(dt.Rows.Count > 0)
                {
                    /** Loop through a list of teams */
                    foreach (DataRow r in dt.Rows)
                    {
                        String u = r["gebruikersnaam"].ToString();
                        String f = r["voornaam"].ToString();
                        String l = r["naam"].ToString();

                        /** Add the current record to the ListView */
                        lvw.Items.Add(new ListViewItem(new String[] { u, f + " " + l}, sGroup));
                    }
                }
                else
                {
                    /** Add a blank record to the ListView */
                    lvw.Items.Add(new ListViewItem(lmLang.GetString("compos.errNoComps"), sGroup));
                }
            }
            catch (Exception e)
            {
                /** Error getting a list of competitors */
                MessageBox.Show(lmLang.GetString("compos.errCompList") + "\n" + e.Message);
            }
        }

        /**
         * ComposForm::checkSignupTeam
         * Take a game ID and a user ID and check if the user has signed up for a team game.
         */
        private bool checkSignup(String gId)
        {
            /** Return value */
            bool rVal;
            /** Query */
            String cQry = "EXEC lmCheckSignup @GameId = '" + gId + "', @UserId = '" + this.lmUser.ID.ToString() + "'";
            /** Get SQL connection */
            SqlConnection dbConn = this.roDb.getDbConn();

            try
            {
                /** Open connection */
                dbConn.Open();
                /** Get DB reader */
                SqlDataReader dbRead = roDb.getDbReader(cQry);

                /** Check for results */
                if (dbRead.HasRows)
                    rVal = true;
                else
                    rVal = false;

                /** Close DB connection */
                dbConn.Close();
            }
            catch (Exception e)
            {
                MessageBox.Show(lmLang.GetString("compos.errGetSignup") + "\n" + e.Message);
                dbConn.Close();
                return false;
            }

            /** Return the result */
            return rVal;
        }

        /**
         * ComposForm::rebindJoin
         * Rebinds the Join button's event handler to the solo handler or the team handler.
         */
        private void rebindJoin(String reTarg)
        {
            /** Unbind the two possible existing event handlers */
            this.btnRegister.Click -= btnRegister_Click_Team;
            this.btnRegister.Click -= btnRegister_Click_Solo;

            if(reTarg == "solo")
                /** Binds the button to Solo */
                this.btnRegister.Click += btnRegister_Click_Solo;
            else if(reTarg == "team")
                /** Binds the button to Team */
                this.btnRegister.Click += btnRegister_Click_Team;
        }
        #endregion

        #region Event Handlers

        /**
         * Event: ComposForm~ClientSizeChanged
         * Window resize event.
         */
        private void ComposForm_ClientSizeChanged(object sender, EventArgs e)
        {
            /** Resize ListView tiles */
            lvwGames.TileSize = new Size(lvwGames.ClientSize.Width, lvwGames.TileSize.Height);
            lvwTeams.TileSize = new Size(lvwTeams.ClientSize.Width/3, lvwTeams.TileSize.Height);
        }

        /** 
         * Event: ComposForm~Load
         * Form Initialization
         */
        private void ComposForm_Load(object sender, EventArgs e)
        {
            try
            {
                loadGames(this.lvwGames);
                this.lvwTeams.Items.Add(lmLang.GetString("compos.lvwTeamsSelect"));
            }
            catch (Exception ex)
            {
                MessageBox.Show(lmLang.GetString("compos.errGameList") + "\n" + ex.Message);
            }
        }

        /**
         * Event: ComposForm::lvwGames~ItemSelectionChanged
         * Event triggered after a change in selection state of lvwGames.
         * Gets called right before SelectedIndexChanged.
         */
        private void lvwGames_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            //MessageBox.Show("ItemSelectionChanged");
        }

        /**
         * Event: ComposForm::lvwGames~SelectedIndexChanged
         * Event triggered after one of the items got selected or deselected.
         * Gets called after ItemSelectionChanged.
         */
        private void lvwGames_SelectedIndexChanged(object sender, EventArgs e)
        {
            //MessageBox.Show("SelectedIndexChanged");
            /** Make sure we have an item selected */
            if (lvwGames.SelectedItems.Count > 0)
            {
                /** Save the current selection state */
                this.SelectedGame = Convert.ToUInt32(lvwGames.SelectedItems[0].Tag.ToString());
                /** Clear the Teams ListView */
                this.lvwTeams.Clear();

                /** Extract row variables */
                String EntryGroup = lvwGames.SelectedItems[0].Group.Name;
                String EntryGameId = lvwGames.SelectedItems[0].Tag.ToString();

                /** Check whether a solo game or a team game has been selected */
                if (EntryGroup == "solo")
                {
                    /** Load a list of competitors */
                    loadCompetitors(EntryGameId, this.lvwTeams);

                    /** Check if the user's already enrolled in the highlighted team competition */
                    if (checkSignup(EntryGameId))
                    {
                        /** Disable the Join button */
                        this.btnRegister.Enabled = false;
                    }
                    else
                    {
                        /** Enable the Join button and bind it to the team join screen */
                        this.btnRegister.Enabled = true;
                    }
                }
                else if (EntryGroup == "team")
                {
                    /** Load a list of teams */
                    loadTeams(EntryGameId, this.lvwTeams);

                    /** Check if the user's already enrolled in the highlighted team competition */
                    if (checkSignup(EntryGameId))
                    {
                        /** Disable the Join button */
                        this.btnRegister.Enabled = false;
                    }
                    else
                    {
                        /** Enable the Join button */
                        this.btnRegister.Enabled = true;
                    }
                }

                /** Rebind the Join button */
                rebindJoin(EntryGroup);
            }
        }

        void btnRegister_Click_Solo(object sender, EventArgs e)
        {
            MessageBox.Show("Signing up for solo game " + this.SelectedGame);
        }

        void btnRegister_Click_Team(object sender, EventArgs e)
        {
            MessageBox.Show("Signing up team for game " + this.SelectedGame);
        }

        private void btnCreateTeam_Click(object sender, EventArgs e)
        {
            CreateTeam ctForm = new CreateTeam(lmLang, lmUser);
            ctForm.ShowDialog();
        }

        #endregion
    }
}